import { Injectable } from '@angular/core';

/**
 * Common LoggerService - Use to log messages, it has 4 levels of logs: 
 * 1. Infomation
 * 2. Warning
 * 3. Error
 * 4. Fatal
 * Exception details or stack trace was highly preferred, exception when you  catch Error and Fatal logs.
 * @export
 * @class LoggerService
 */
@Injectable()
export class LoggerService {
    /**
     * contruction method.
     * 
     * @memberOf LoggerService
     */
    consturctor() { }

    //Logger for normal message function.
    /**
     * Infomation log function.
     * 
     * @param {LoggerInfo} info
     * 
     * @memberOf LoggerService
     */
    info(info: LoggerInfo): void {
        let entity: LoggerEntity = new LoggerEntity();
        entity.LoggerType = LoggType.Info;
        entity.LoggerInfo = info;
        this._LOG(entity);
    }

    //Logger for warning message function.
    /**
     * Warning log function.
     * 
     * @param {LoggerInfo} info
     * 
     * @memberOf LoggerService
     */
    warning(info: LoggerInfo): void {
        let entity: LoggerEntity = new LoggerEntity();
        entity.LoggerType = LoggType.Warning;
        entity.LoggerInfo = info;
        this._LOG(entity);
    }

    //Logger for error message function.
    /**
     * Error log funciton.
     * 
     * @param {LoggerInfo} info
     * 
     * @memberOf LoggerService
     */
    error(info: LoggerInfo): void {
        let entity: LoggerEntity = new LoggerEntity();
        entity.LoggerType = LoggType.Error;
        entity.LoggerInfo = info;
        this._LOG(entity);
    }

    //Logger for fatal message function.
    /**
     * Fatal log function.
     * 
     * @param {LoggerInfo} info
     * 
     * @memberOf LoggerService
     */
    fatal(info: LoggerInfo): void {
        let entity: LoggerEntity = new LoggerEntity();
        entity.LoggerType = LoggType.Fatal;
        entity.LoggerInfo = info;
        this._LOG(entity);
    }

    //Execute log handler.
    /**
     * private common log function. all exposed function will invoke this method.
     * TODO: Now we only provide console.log(), for future, we will provide for logs uploading.
     * 
     * @private
     * @param {LoggerEntity} entity
     * 
     * @memberOf LoggerService
     */
    private _LOG(entity: LoggerEntity): void {
        let output:string;
        output= `LogType - ${entity.LoggerType.toString()}, Component - ${entity.LoggerInfo.LoggerComponent}, LogMessage - ${entity.LoggerInfo.LoggerMessage}, Exception - { ${entity.LoggerInfo.LoggerException} }`;
        console.log(output);
    }
}

/**
 * Logger Entity for Logging Service. (final entity)
 * @export
 * @class LoggerEntity
 */
class LoggerEntity {
    /**
     * Logger type, will be initial on LoggerService class, no need to assignment by users.
     * 
     * @type {LoggType}
     * @memberOf LoggerEntity
     */
    LoggerType: LoggType;
    /**
     * users provided. users can customize it.
     * 
     * @type {LoggerInfo}
     * @memberOf LoggerEntity
     */
    LoggerInfo: LoggerInfo;
}

/**
 * External Logger entity, users need export this class for logging.
 * 
 * @export
 * @class LoggerInfo
 */
export class LoggerInfo {
    /**
     * Trigger Componenet.
     * 
     * @type {string}
     * @memberOf LoggerInfo
     */
    LoggerComponent: string;
    /**
     * Logger information message.
     * 
     * @type {string}
     * @memberOf LoggerInfo
     */
    LoggerMessage: string;
    /**
     * Exceptions.
     * 
     * @type {*}
     * @memberOf LoggerInfo
     */
    LoggerException: any;

    /**
     * Creates an instance of LoggerInfo.
     * 
     * @param {string} loggerComponent
     * @param {string} loggerMessage
     * @param {*} loggerException
     * 
     * @memberOf LoggerInfo
     */
    constructor(loggerComponent: string, loggerMessage: string, loggerException: any) {
        this.LoggerComponent = loggerComponent;
        this.LoggerMessage = loggerMessage;
        this.LoggerException = loggerException;
    }
}

/**
 * Logger Level - Now we provide 4 levels of log.
 * 
 * @export
 * @enum {number}
 */
export enum LoggType {
    /**
     * 
     */
    Info,
    /**
     * 
     */
    Warning,
    /**
     * 
     */
    Error,
    /**
     * 
     */
    Fatal
}